package com.kmxd.ams.app.arrange;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps;
import com.kmxd.ams.client.archive.IArchiveRuleCatalogSvc;
import com.kmxd.ams.client.archive.IArchiveTypeSvc;
import com.kmxd.ams.client.archive.dto.ArchiveRuleCatalogQueryDTO;
import com.kmxd.ams.client.archive.vo.ArchiveRuleCatalogListVO;
import com.kmxd.ams.client.archive.vo.ArchiveRuleCatalogVO;
import com.kmxd.ams.client.archive.vo.ArchiveTypeVO;
import com.kmxd.ams.client.arrange.*;
import com.kmxd.ams.client.arrange.dto.*;
import com.kmxd.ams.client.arrange.vo.ArchCategoryVO;
import com.kmxd.ams.client.arrange.vo.CatalogListVO;
import com.kmxd.ams.client.arrange.vo.CatalogVO;
import com.kmxd.ams.core.common.bo.ConditionBO;
import com.kmxd.ams.core.common.bo.GroupFieldBO;
import com.kmxd.ams.core.common.constant.ArchConst;
import com.kmxd.ams.core.common.constant.ConfigConst;
import com.kmxd.ams.core.common.constant.Constants;
import com.kmxd.ams.core.common.enums.CatalogTypeEnum;
import com.kmxd.ams.core.common.enums.FieldOrderTypeEnum;
import com.kmxd.ams.core.common.query.QueryGen;
import com.kmxd.ams.core.util.*;
import com.kmxd.ams.infra.arrange.base.SystemBO;
import com.kmxd.ams.infra.arrange.entity.*;
import com.kmxd.ams.infra.arrange.mapper.CatalogMapper;
import com.kmxd.ams.infra.tmpl.dto.ArchTmplBO;
import com.kmxd.ams.infra.tmpl.enums.TmplRes;
import com.kmxd.ams.infra.tmpl.util.TmplCommon;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 * 目录树管理 服务实现类
 *
 * @author nickbi
 * @since 2022-08-04
 */
@Service
@RequiredArgsConstructor
public class CatalogSvcImpl extends ServiceImpl<CatalogMapper, Catalog> implements ICatalogSvc {

  private final CatalogMapper catalogMapper;
  private final IArchiveRuleCatalogSvc archiveRuleCatalogSvc;
  private final TmplCommon tmplCommon;
  private Cache<Object, Object> cache;

  @PostConstruct
  public void init() {
    if (Objects.isNull(cache)) {
      cache = CacheBuilder.newBuilder().build();
    }
  }

  @Override
  public Page<CatalogListVO> selectPage(Page reqPage, CatalogQueryDTO req) {
    LambdaQueryWrapper<Catalog> queryWrapper =
        QueryGen.init(new QueryWrapper<Catalog>(), req).lambda();
    Page<Catalog> page = catalogMapper.selectPage(reqPage, queryWrapper);
    Page<CatalogListVO> voPage = BeanUtil.copyProperties(page, Page.class);
    voPage.setRecords(BeanUtil.copyToList(page.getRecords(), CatalogListVO.class));
    return voPage;
  }

  @Override
  public List<CatalogListVO> selectList(CatalogQueryDTO req) {
    LambdaQueryWrapper<Catalog> queryWrapper =
        QueryGen.init(new QueryWrapper<Catalog>(), req).lambda();
    List<Catalog> list = catalogMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, CatalogListVO.class);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void add(CatalogAddDTO req) {
    Catalog entity = BeanUtil.copyProperties(req, Catalog.class);
    catalogMapper.insert(entity);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void edit(CatalogEditDTO req) {
    Catalog entity = BeanUtil.copyProperties(req, Catalog.class);
    catalogMapper.updateById(entity);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(String ids) {
    Set<Long> idList = IdUtil.split(ids);
    this.baseMapper.deleteBatchIds(idList);
  }

  @Override
  public CatalogVO view(Long id) {
    Catalog entity = catalogMapper.selectById(id);
    return BeanUtil.copyProperties(entity, CatalogVO.class);
  }

  @Override
  public List<Tree<String>> tree(CatalogTreeQueryDTO req) {
    Boolean allFlag = false;
    if (Objects.isNull(req.getPid()) || ObjectUtil.equals(0L, req.getPid())) {
      allFlag = true;
    }
    List<Tree<String>> tree = tree(req, allFlag);
    return tree;
  }

  @Override
  public List<Tree<String>> tree(CatalogTreeQueryDTO req, Boolean allFlag) {
    if (Objects.isNull(req.getPid())) {
      req.setPid(0L);
    }
    if (ObjectUtil.isNull(req.getStatus())) {
      req.setStatus(req.getManageType());
    }

    ArchiveRuleCatalogQueryDTO qryRule = new ArchiveRuleCatalogQueryDTO();
    qryRule.setStatus(req.getStatus());
    // 默认节点，查询时使用默认节点状态查询
    boolean customFlag =
        archiveRuleCatalogSvc.getCustomFlag(
            SecurityUtil.getCropId(), SecurityUtil.getFondsId(), qryRule.getStatus());
    if (!customFlag) {
      qryRule.setStatus(Constants.CATALOG_DEFAULT_STATUS);
    }
    ArchiveRuleCatalogVO view = archiveRuleCatalogSvc.view(req.getPid());
    qryRule.setPid(req.getPid());
    qryRule.setComId(SecurityUtil.getCropId());
    qryRule.setFondsId(SecurityUtil.getFondsId());

    List<Tree<String>> trees = Lists.newArrayList();
    // 父节点为对象节点，查询分组节点
    if (ObjectUtil.isNotEmpty(view)
        && CatalogTypeEnum.ARCH_MODEL_NODE.equals(CatalogTypeEnum.convert(view.getType()))) {
      buildGroupNode(req, view, trees);
      // 分组条件大于0，表面已经有其他分组条件，直接返回剩余分组节点
      Integer groupIndex = Optional.ofNullable(req.getGroupIndex()).orElse(0);
      if (groupIndex > 0) {
        return trees;
      }
    }
    List<ArchiveRuleCatalogListVO> ruleCatalogList = archiveRuleCatalogSvc.selectList(qryRule);
    if (ObjectUtil.isEmpty(ruleCatalogList)) {
      return trees;
    }
    if (ObjectUtil.isNotEmpty(view) && CatalogTypeEnum.ARCH_NODE.getCode() == view.getType()) {
      // 门类对象节点，特殊处理
      if (BooleanUtil.isTrue(req.getUseEs())) {
        buildFrontArchModelNode(req, view, trees, ruleCatalogList);
      } else {
        buildArchModelNode(req, view, trees, ruleCatalogList);
      }
    } else {
      // 其他节点
      ruleCatalogList.forEach(
          item -> {
            CatalogTypeEnum typeEnum = CatalogTypeEnum.convert(item.getType());
            switch (typeEnum) {
                // 数据节点
              case CONDITION_NODE:
                Tree<String> tree = buildConditionNode(req, item);
                trees.add(tree);
                return;
                // 目录节点
              case DIR_NODE:
                Tree<String> dirNode = buildDirNode(req, item);
                trees.add(dirNode);
                return;
                // 门类节点：
              case ARCH_NODE:
                Tree<String> archNode = buildArchNode(req, item);
                trees.add(archNode);
            }
          });
    }
    return trees;
  }

  private void buildArchModelNode(
      CatalogTreeQueryDTO req,
      ArchiveRuleCatalogVO view,
      List<Tree<String>> trees,
      List<ArchiveRuleCatalogListVO> ruleCatalogList) {
    // 档案类型
    IArchiveTypeSvc archiveTypeSvc = SpringUtil.getBean(IArchiveTypeSvc.class);
    ArchiveTypeVO archType = archiveTypeSvc.view(view.getArchTypeId());
    String manageModel = archType.getManageModel();

    Map<String, ArchiveRuleCatalogListVO> groupMap =
        ruleCatalogList.stream()
            .collect(Collectors.toMap(ArchiveRuleCatalogListVO::getTableId, Function.identity()));
    // 按档案类型，获取门类对象节点信息，拼接门类对象节点
    List<ArchCategoryVO> list =
        tmplCommon.getTempInfoList(
            TmplRes.ARCH_CATEGORY_PATH.getPath() + manageModel + ".json", ArchCategoryVO.class);
    Map<Long, ArchiveRuleCatalogListVO> ruleMap = getAllRuleList(req);
    List<ConditionBO> dataCondition =
        Optional.ofNullable(JSONUtils.toList(req.getDataCondition(), ConditionBO.class))
            .orElse(Lists.newArrayList());
    list.forEach(
        item -> {
          ArchiveRuleCatalogListVO vo =
              groupMap.get(ConvertUtil.getValue(archType, item.getTableId(), String.class));
          Tree<String> archModelNode = buildArchModelNode(req, vo);
          archModelNode.setName(item.getName());
          archModelNode.putExtra(ArchConst.SCATTERED_STATUS, item.getScatteredStatus());
          // 数据节点拼接
          List<ConditionBO> dataNode = buildDataNode(vo, ruleMap);
          if (ObjectUtil.isNotEmpty(dataNode)) {
            List<ConditionBO> conditionList = BeanUtil.copyToList(dataCondition, ConditionBO.class);
            conditionList.addAll(dataNode);
            archModelNode.putExtra(
                Constants.CATALOG_DATA_CONDITION_FIELD, JSONUtil.toJsonStr(conditionList));
          }
          archModelNode.put(Constants.CATALOG_KEY_FIELD, IdWorker.getIdStr());
          trees.add(archModelNode);
        });
  }

  private void buildFrontArchModelNode(
      CatalogTreeQueryDTO req,
      ArchiveRuleCatalogVO view,
      List<Tree<String>> trees,
      List<ArchiveRuleCatalogListVO> ruleCatalogList) {
    // 档案类型
    IArchiveTypeSvc archiveTypeSvc = SpringUtil.getBean(IArchiveTypeSvc.class);
    ArchiveTypeVO archType = archiveTypeSvc.view(view.getArchTypeId());
    String manageModel = archType.getManageModel();

    Map<String, ArchiveRuleCatalogListVO> groupMap =
        ruleCatalogList.stream()
            .collect(Collectors.toMap(ArchiveRuleCatalogListVO::getTableId, Function.identity()));
    // 按档案类型，获取门类对象节点信息，拼接门类对象节点
    List<ArchCategoryVO> list =
        tmplCommon.getTempInfoList(
            TmplRes.ARCH_FRONT_CATEGORY_PATH.getPath() + manageModel + ".json",
            ArchCategoryVO.class);
    Map<Long, ArchiveRuleCatalogListVO> ruleMap = getAllRuleList(req);
    List<ConditionBO> dataCondition =
        Optional.ofNullable(JSONUtils.toList(req.getDataCondition(), ConditionBO.class))
            .orElse(Lists.newArrayList());
    list.forEach(
        item -> {
          ArchiveRuleCatalogListVO vo =
              groupMap.get(ConvertUtil.getValue(archType, item.getTableId(), String.class));
          Tree<String> archModelNode = buildArchModelNode(req, vo);
          archModelNode.setName(item.getName());
          archModelNode.putExtra(ArchConst.SCATTERED_STATUS, item.getScatteredStatus());
          // 数据节点拼接
          List<ConditionBO> dataNode = buildDataNode(vo, ruleMap);
          if (ObjectUtil.isNotEmpty(dataNode)) {
            List<ConditionBO> conditionList = BeanUtil.copyToList(dataCondition, ConditionBO.class);
            conditionList.addAll(dataNode);
            archModelNode.putExtra(
                Constants.CATALOG_DATA_CONDITION_FIELD, JSONUtil.toJsonStr(conditionList));
          }
          archModelNode.put(Constants.CATALOG_KEY_FIELD, IdWorker.getIdStr());
          trees.add(archModelNode);
        });
  }

  private void buildGroupNode(
      CatalogTreeQueryDTO req, ArchiveRuleCatalogVO view, List<Tree<String>> trees) {
    String nodeCondition = view.getNodeCondition();
    if (CharSequenceUtil.isBlank(nodeCondition)) {
      return;
    }
    ArchiveRuleCatalogListVO item = BeanUtil.copyProperties(view, ArchiveRuleCatalogListVO.class);
    List<Tree<String>> groupNode = buildGroupNode(req, item);
    if (ObjectUtil.isEmpty(groupNode)) {
      return;
    }
    List<Tree<String>> sortTree = sortCatalog(groupNode, req, item);
    trees.addAll(sortTree);
  }

  /**
   * 创建门类对象节点
   *
   * @param req
   * @param item
   * @return
   */
  private Tree<String> buildArchModelNode(CatalogTreeQueryDTO req, ArchiveRuleCatalogListVO item) {
    Tree<String> treeNode = new Tree();
    treeNode.setId(item.getId().toString());
    treeNode.setName(item.getName());
    treeNode.setParentId(req.getPid().toString());
    treeNode.setWeight(item.getSort());
    treeNode.putExtra(Constants.CATALOG_TYPE_FIELD, CatalogTypeEnum.ARCH_MODEL_NODE.getCode());
    setArchInfo(item, treeNode);

    return treeNode;
  }

  /**
   * 创建门类节点
   *
   * @param req
   * @param item
   * @return
   */
  private Tree<String> buildArchNode(CatalogTreeQueryDTO req, ArchiveRuleCatalogListVO item) {
    Tree<String> treeNode = new Tree();
    treeNode.setId(item.getId().toString());
    treeNode.setName(item.getName());
    treeNode.setParentId(req.getPid().toString());
    treeNode.setWeight(item.getSort());
    treeNode.putExtra(Constants.CATALOG_TYPE_FIELD, CatalogTypeEnum.ARCH_NODE.getCode());
    if (ObjectUtil.isNotEmpty(req.getDataCondition())) {
      treeNode.putExtra(Constants.CATALOG_DATA_CONDITION_FIELD, req.getDataCondition());
    }
    treeNode.put(Constants.CATALOG_KEY_FIELD, item.getId().toString());
    setArchInfo(item, treeNode);
    return treeNode;
  }

  /**
   * 目录节点
   *
   * @param req
   * @param item
   * @return
   */
  private Tree<String> buildDirNode(CatalogTreeQueryDTO req, ArchiveRuleCatalogListVO item) {
    Tree<String> treeNode = new Tree();
    treeNode.setId(item.getId().toString());
    treeNode.setName(item.getName());
    treeNode.setParentId(req.getPid().toString());
    treeNode.setWeight(item.getSort());
    treeNode.putExtra(Constants.CATALOG_TYPE_FIELD, CatalogTypeEnum.DIR_NODE.getCode());
    if (ObjectUtil.isNotEmpty(req.getDataCondition())) {
      treeNode.putExtra(Constants.CATALOG_DATA_CONDITION_FIELD, req.getDataCondition());
    }
    treeNode.put(Constants.CATALOG_KEY_FIELD, IdWorker.getIdStr());

    setArchInfo(item, treeNode);

    return treeNode;
  }

  /**
   * 分组节点
   *
   * @param req
   * @param item
   * @return
   */
  private List<Tree<String>> buildGroupNode(
      CatalogTreeQueryDTO req, ArchiveRuleCatalogListVO item) {
    if (ObjectUtil.isEmpty(req.getGroupIndex())) {
      req.setGroupIndex(0);
    }
    String condition = item.getNodeCondition();
    List<GroupFieldBO> conditionList = JSONUtils.toList(condition, GroupFieldBO.class);
    if (ObjectUtil.isEmpty(conditionList)) {
      return null;
    }
    if (BooleanUtil.isTrue(req.getUseEs())) {
      return getGroupDataFromEs(req, item, conditionList);
    } else {
      return getGroupData(req, item, conditionList);
    }
  }

  /**
   * 分组数据统计
   *
   * @param req
   * @param item
   * @param groupArray
   * @return
   */
  private List<Tree<String>> getGroupData(
      CatalogTreeQueryDTO req, ArchiveRuleCatalogListVO item, List<GroupFieldBO> groupArray) {
    if (groupArray.size() <= req.getGroupIndex()) {
      return null;
    }
    GroupFieldBO groupObj = groupArray.get(req.getGroupIndex());
    if (ObjectUtil.isEmpty(groupObj)) {
      return null;
    }
    String tableId = item.getTableId();
    String fieldKey = groupObj.getFieldKey();
    QueryWrapper<? extends SystemBO> query = Wrappers.query();
    //    query.select("DISTINCT " + fieldKey);
    query.select(fieldKey);
    query.eq(ArchConst.ARCH_STATUS, req.getStatus());
    Map<String, String> groupCondition =
        Optional.ofNullable(req.getGroupCondition()).orElse(Maps.newHashMap());
    if (ObjectUtil.isNotEmpty(groupCondition)) {
      groupCondition.forEach(
          (key, value) -> {
            String field = StringUtils.camelToUnderline(key);
            // 空值查询
            if (CharSequenceUtil.equals(Constants.QUERY_NULL_DATA_PLACEHOLDER, value)) {
              query.isNull(field);
            } else {
              // 非空值查询
              query.eq(field, value);
            }
          });
    }
    // 用户状态信息
    //    Long manageStatus = SecurityUtil.getManageStatus();
    //    query.eq(FieldUtil.getColumn(Document::getManageStatus), manageStatus);
    //    if (NumberUtil.equals(0L, manageStatus)) {
    //      // 个人用户，只能查询自己的数据
    //      query.eq(ArchConst.CREATE_BY, SecurityUtil.getUserId());
    //    }

    // 设置分组字段信息
    query.groupBy(fieldKey);
    // 设置数据节点过滤
    List<ConditionBO> dataCondition =
        Optional.ofNullable(JSONUtils.toList(req.getDataCondition(), ConditionBO.class))
            .orElse(Lists.newArrayList());
    String dataConditionSql = QueryUtil.buildDataSql(JSONUtil.toJsonStr(dataCondition));
    if (CharSequenceUtil.isNotBlank(dataConditionSql)) {
      query.apply(dataConditionSql);
    }
    List<? extends SystemBO> list = Lists.newArrayList();
    if (CharSequenceUtil.contains(tableId, ArchTmplBO.DOCUMENT)) {
      // 散文件
      if (BooleanUtil.isTrue(req.getScatteredStatus())) {
        buildScatteredQuery(req, query);
      }
      IDocumentSvc documentSvc = SpringUtil.getBean(IDocumentSvc.class);
      DynamicTableNameUtil.setTableName(tableId);
      list = documentSvc.list((Wrapper<Document>) query);
    }
    if (CharSequenceUtil.contains(tableId, ArchTmplBO.VOLUME)) {
      IVolumeSvc volumeSvc = SpringUtil.getBean(IVolumeSvc.class);
      DynamicTableNameUtil.setTableName(tableId);
      list = volumeSvc.list((Wrapper<Volume>) query);
    }
    if (CharSequenceUtil.contains(tableId, ArchTmplBO.BOX)) {
      IBoxSvc boxSvc = SpringUtil.getBean(IBoxSvc.class);
      DynamicTableNameUtil.setTableName(tableId);
      list = boxSvc.list((Wrapper<Box>) query);
    }

    if (CharSequenceUtil.contains(tableId, ArchTmplBO.PROJECT)) {
      IProjectSvc projectSvc = SpringUtil.getBean(IProjectSvc.class);
      DynamicTableNameUtil.setTableName(tableId);
      list = projectSvc.list((Wrapper<Project>) query);
    }

    if (ObjectUtil.isEmpty(list)) {
      return null;
    }
    int nextGroupIndex = req.getGroupIndex() + 1;
    Map<Long, ArchiveRuleCatalogListVO> ruleMap = getAllRuleList(req);

    return list.stream()
        .map(
            arch -> {
              Tree<String> treeNode = new Tree();
              treeNode.setId(req.getPid().toString());
              String camelFieldKey = StringUtils.underlineToCamel(fieldKey);
              String value = ConvertUtil.getValue(arch, camelFieldKey, String.class);
              // 如果是null，显示为--
              String fieldValue =
                  StrUtil.isBlank(value) ? Constants.QUERY_NULL_DATA_PLACEHOLDER : value;
              String name = ObjectUtil.isEmpty(value) ? Constants.CATALOG_PLACEHOLDER : value;

              treeNode.setName(name);
              treeNode.setParentId(req.getPid().toString());
              treeNode.setWeight(item.getSort());
              treeNode.putExtra(ArchConst.ARCH_TYPE_ID, item.getArchTypeId().toString());
              treeNode.put(ArchConst.TABLE_ID, item.getTableId());
              treeNode.putExtra(Constants.CATALOG_TYPE_FIELD, CatalogTypeEnum.GROUP_NODE.getCode());
              if (BooleanUtil.isTrue(req.getScatteredStatus())) {
                treeNode.putExtra(ArchConst.SCATTERED_STATUS, req.getScatteredStatus());
              }
              Map<String, String> newGroupCondition = Maps.newHashMap();
              newGroupCondition.putAll(groupCondition);
              newGroupCondition.put(camelFieldKey, fieldValue);
              // 分组节点
              treeNode.putExtra(Constants.CATALOG_group_CONDITION_FIELD, newGroupCondition);
              treeNode.putExtra(
                  FieldUtil.getFieldName(CatalogTreeQueryDTO::getGroupIndex), nextGroupIndex);
              ArchiveTypeVO archType =
                  SpringUtil.getBean(IArchiveTypeSvc.class).view(item.getArchTypeId());
              // 门类信息
              treeNode.putExtra(Constants.CATALOG_ARCH_INFO_FIELD, archType);

              // 数据节点拼接
              List<ConditionBO> dataNode = buildDataNode(item, ruleMap);
              if (ObjectUtil.isNotEmpty(dataNode)) {
                dataCondition.addAll(dataNode);
                treeNode.putExtra(
                    Constants.CATALOG_DATA_CONDITION_FIELD, JSONUtil.toJsonStr(dataCondition));
              }
              treeNode.put(Constants.CATALOG_KEY_FIELD, IdWorker.getIdStr());
              setArchInfo(item, treeNode);
              return treeNode;
            })
        .collect(Collectors.toList());
  }

  private List<Tree<String>> getGroupDataFromEs(
      CatalogTreeQueryDTO req, ArchiveRuleCatalogListVO item, List<GroupFieldBO> groupArray) {

    return null;
  }

  private Class<? extends SystemBO> getEsRecordClass(String tableId) {
    return SystemBO.class;
  }

  private String buildDataConditionToEsQuery(String dataConditionSql) {
    if (CharSequenceUtil.isBlank(dataConditionSql)) {
      return null;
    }
    return null;
  }

  private static void buildScatteredQuery(
      CatalogTreeQueryDTO req, QueryWrapper<? extends SystemBO> query) {
    IArchiveTypeSvc archiveTypeSvc = SpringUtil.getBean(IArchiveTypeSvc.class);
    ArchiveTypeVO archiveTypeVO = archiveTypeSvc.view(req.getArchTypeId());
    if (ObjectUtil.isEmpty(archiveTypeVO)) {
      return;
    }
    if (archiveTypeVO.getManageModel().contains("box")) {
      query.isNull(ArchConst.BOX_ID_DB);
    } else {
      query.isNull(ArchConst.VOL_ID_DB);
    }
  }

  private List<ConditionBO> buildDataNode(
      ArchiveRuleCatalogListVO item, Map<Long, ArchiveRuleCatalogListVO> ruleMap) {
    List<ConditionBO> dataCondition = Lists.newArrayList();
    buildParentDataNode(item, ruleMap, dataCondition);
    return dataCondition;
  }

  private Map<Long, ArchiveRuleCatalogListVO> getAllRuleList(CatalogTreeQueryDTO req) {
    ArchiveRuleCatalogQueryDTO qryRule = new ArchiveRuleCatalogQueryDTO();
    // 默认节点，查询时使用默认节点状态查询
    String configValue =
        ConfigUtil.getConfigValue(ConfigConst.CATALOG_CONFIG + ":" + req.getStatus());
    boolean custom = Boolean.parseBoolean(configValue);
    if (!custom) {
      qryRule.setStatus(Constants.CATALOG_DEFAULT_STATUS);
    }
    qryRule.setComId(SecurityUtil.getCropId());
    qryRule.setFondsId(SecurityUtil.getFondsId());
    List<ArchiveRuleCatalogListVO> allRuleList = archiveRuleCatalogSvc.selectList(qryRule);
    return allRuleList.stream()
        .collect(Collectors.toMap(ArchiveRuleCatalogListVO::getId, Function.identity()));
  }

  private void buildParentDataNode(
      ArchiveRuleCatalogListVO item,
      Map<Long, ArchiveRuleCatalogListVO> ruleMap,
      List<ConditionBO> list) {
    if (ObjectUtil.isEmpty(item)) {
      return;
    }

    setDataCondition(list, item);

    ArchiveRuleCatalogListVO parentNode = ruleMap.get(item.getPid());
    if (ObjectUtil.isEmpty(parentNode)) {
      return;
    }
    if (ObjectUtil.notEqual(0L, parentNode.getPid())) {
      buildParentDataNode(parentNode, ruleMap, list);
    }
  }

  /**
   * 设置数据节点，数据条件
   *
   * @param list
   * @param parentNode
   */
  private void setDataCondition(List<ConditionBO> list, ArchiveRuleCatalogListVO parentNode) {
    CatalogTypeEnum typeEnum = CatalogTypeEnum.convert(parentNode.getType());
    if (CharSequenceUtil.isBlank(parentNode.getNodeCondition())) {
      return;
    }
    if (ObjectUtil.notEqual(CatalogTypeEnum.CONDITION_NODE, typeEnum)) {
      return;
    }
    List<ConditionBO> boList = JSONUtils.toList(parentNode.getNodeCondition(), ConditionBO.class);
    if (ObjectUtil.isEmpty(boList)) {
      return;
    }
    list.addAll(boList);
  }

  /**
   * 创建数据节点
   *
   * @param req
   * @param item
   * @return
   */
  private Tree<String> buildConditionNode(CatalogTreeQueryDTO req, ArchiveRuleCatalogListVO item) {
    Tree<String> treeNode = new Tree<>();
    treeNode.setId(item.getId().toString());
    treeNode.setName(item.getName());
    treeNode.setParentId(req.getPid().toString());
    treeNode.setWeight(item.getSort());

    if (ObjectUtil.isNotEmpty(item.getArchTypeId())) {
      ArchiveTypeVO archType = SpringUtil.getBean(IArchiveTypeSvc.class).view(item.getArchTypeId());
      treeNode.putExtra(Constants.CATALOG_ARCH_INFO_FIELD, archType);
    }
    if (BooleanUtil.isTrue(req.getScatteredStatus())) {
      treeNode.putExtra(ArchConst.SCATTERED_STATUS, req.getScatteredStatus());
    }

    // 数据节点拼接
    Map<Long, ArchiveRuleCatalogListVO> ruleMap = getAllRuleList(req);
    List<ConditionBO> dataNode = buildDataNode(item, ruleMap);

    if (ObjectUtil.isNotEmpty(dataNode)) {
      treeNode.putExtra(Constants.CATALOG_DATA_CONDITION_FIELD, JSONUtil.toJsonStr(dataNode));
    }
    treeNode.putExtra(Constants.CATALOG_TYPE_FIELD, CatalogTypeEnum.CONDITION_NODE.getCode());
    setArchInfo(item, treeNode);
    treeNode.put(Constants.CATALOG_KEY_FIELD, IdWorker.getIdStr());
    return treeNode;
  }

  private void setArchInfo(ArchiveRuleCatalogListVO item, Tree<String> treeNode) {
    if (ObjectUtil.isNotNull(item.getArchTypeId())) {
      ArchiveTypeVO archType = SpringUtil.getBean(IArchiveTypeSvc.class).view(item.getArchTypeId());
      // 门类信息
      treeNode.putExtra(Constants.CATALOG_ARCH_INFO_FIELD, archType);
      treeNode.putExtra(ArchConst.ARCH_TYPE_ID, item.getArchTypeId());
    }
    // 设置节点对象类型
    if (CharSequenceUtil.isNotBlank(item.getTableId())) {
      treeNode.putExtra(ArchConst.TABLE_ID, item.getTableId());
      String typeModel = getTypeModel(item.getTableId());
      treeNode.putExtra(Constants.CATALOG_TYPE_MODEL_FIELD, typeModel);
    }
  }

  private List<Tree<String>> sortCatalog(
      List<Tree<String>> treeList, CatalogTreeQueryDTO req, ArchiveRuleCatalogListVO catalog) {
    if (ObjectUtil.isEmpty(treeList)) {
      return Lists.newArrayList();
    }
    String nodeCondition = catalog.getNodeCondition();
    List<GroupFieldBO> ruleList = JSONUtils.toList(nodeCondition, GroupFieldBO.class);
    if (ObjectUtil.isEmpty(ruleList)) {
      return CollectionUtils.isEmpty(treeList) ? new ArrayList() : treeList;
    }
    // 分组信息未找到，直接返回
    if (ruleList.size() <= req.getGroupIndex()) {
      return treeList;
    }
    GroupFieldBO groupFieldBO = ruleList.get(req.getGroupIndex());
    if (ObjectUtil.isEmpty(groupFieldBO)) {
      return treeList;
    }
    String key = groupFieldBO.getFieldKey();

    String orderType = groupFieldBO.getOrderType();
    // 数值，格式化为数字然后进行排序
    Tree<String> tree = treeList.get(0);
    Map<String, String> groupData =
        (Map<String, String>) tree.get(Constants.CATALOG_group_CONDITION_FIELD);
    if (ObjectUtil.isEmpty(groupData)) {
      return treeList;
    }

    String value = groupData.get(key);
    boolean number = NumberUtil.isNumber(value);
    if (number) {
      treeList.sort(
          (x, y) -> {
            if (ObjectUtil.isNotEmpty(x.getName()) && ObjectUtil.isNotEmpty(y.getName())) {
              Object xVal = NumberUtil.isNumber(x.getName()) ? x.getName() : 0;
              Object yVal = NumberUtil.isNumber(y.getName()) ? y.getName() : 0;
              return NumberUtil.compare(
                  Integer.parseInt(String.valueOf(xVal)), Integer.parseInt(String.valueOf(yVal)));
            }
            return 0;
          });

    } else {
      // 字符
      treeList.sort((x, y) -> StrUtil.compare(x.getName(), y.getName(), true));
    }
    // 升序
    if (FieldOrderTypeEnum.DESC.getType().equalsIgnoreCase(orderType)) {
      Collections.reverse(treeList);
    }
    return treeList;
  }

  private String getTypeModel(String tableId) {
    if (CharSequenceUtil.isBlank(tableId)) {
      return null;
    }
    if (ObjectUtil.contains(tableId, ArchTmplBO.DOCUMENT)) {
      return ArchTmplBO.DOCUMENT;
    } else if (ObjectUtil.contains(tableId, ArchTmplBO.VOLUME)) {
      return ArchTmplBO.VOLUME;
    } else if (ObjectUtil.contains(tableId, ArchTmplBO.BOX)) {
      return ArchTmplBO.BOX;
    } else {
      return ArchTmplBO.PROJECT;
    }
  }
}
